// 增删改查基类

package web

import (
	"api/common"
	"api/common/logger"
	"api/common/orm"
	"fmt"
	"net/http"
	"reflect"
	"strings"
)

// 分页
type Page struct {
	Success bool   `json:"success"` // 是否成功
	Msg     string `json:"msg"`     // 消息
	Status  int    `json:"status"`  // 状态代码
	Total   int    `json:"total"`   // 总数量

	Root []map[string]interface{} `json:"root"` // 数组
}

// 不分页
type List struct {
	Status  int    `json:"status"`
	Success bool   `json:"success"`
	Msg     string `json:"msg"`

	Data []map[string]interface{} `json:"data"`
}

// 操作结果
type JsonMsg struct {
	Success bool   `json:"success"`
	Msg     string `json:"msg"`
	Status  int    `json:"status"`
}

//数据列表查询
func JsonCallBak(w http.ResponseWriter, r *http.Request, model interface{}, sqlWhere ...string) {
	page, msg := JsonRoot(w, r, model)
	if msg != nil {
		ServeJSON(w, msg)
	} else {
		ServeJSON(w, page) //此次可在子类中增加回调
	}
}

// 按需查询(自定义需要查询的字段和条件)
func JsonCallBakFilter(w http.ResponseWriter, inputJson map[string]interface{}, model interface{}, fields string, sqlWhere string, sqlOrder string) {
	page, msg := JsonRootWithInputFilter(inputJson, model, fields, sqlWhere, sqlOrder)
	if msg != nil {
		ServeJSON(w, msg)
	} else {
		ServeJSON(w, page)
	}
}
func JsonRootWithInputFilter(inputJson map[string]interface{}, model interface{}, fields string, sqlWhere string, sqlOrder string) (*Page, *JsonMsg) {
	wheres, limit := SerachJsonToSql(inputJson)
	where := ""
	if len(wheres) >= 1 {
		where = " where " + strings.Join(wheres, " and ")
	}
	if sqlWhere != "" {
		if len(wheres) >= 1 {
			where += " and " + sqlWhere
		} else {
			where += " where " + sqlWhere
		}
	}

	conn := orm.NewOrm() // orm数据库操作
	tableName, pk := conn.GetTableAndPk(model)
	count := 0
	sql := "select count(1) from " + tableName + where
	err := conn.Raw(sql).QueryRow(&count)
	if err != nil {
		logger.Error("查询记录数量发生错误", err)
		return nil, &JsonMsg{false, "查询记录数量发生错误", 1}
	}

	data := []map[string]interface{}{}
	if count >= 1 {
		if fields == "" {
			fields = "*"
		}
		if sqlOrder == "" {
			sqlOrder = pk + " desc"
		}
		sql = "select " + fields + " from " + tableName + where + " order by " + sqlOrder + limit
		data, err = conn.Raw(sql).QueryMaps()
		if err != nil {
			logger.Error("查询记录发生错误", err)
			return nil, &JsonMsg{false, "查询记录发生错误" + err.Error(), 1}
		}
	}
	return &Page{true, "查询成功", 0, count, data}, nil
}

//数据列表查询
func JsonRoot(w http.ResponseWriter, r *http.Request, model interface{}, sqlWhere ...string) (*Page, *JsonMsg) {
	inputJson, msg := JsonCheckRequest(w, r)
	if msg != nil {
		return nil, msg
	}

	return JsonRootWithInput(inputJson, model, sqlWhere...)
}

// 数据列表查询
func JsonRootWithInput(inputJson map[string]interface{}, model interface{}, sqlWhere ...string) (*Page, *JsonMsg) {
	wheres, limit := SerachJsonToSql(inputJson)
	for _, where := range sqlWhere {
		wheres = append(wheres, where)
	}

	where := ""
	if len(wheres) > 0 {
		where = " where " + strings.Join(wheres, " and ")
	}

	conn := orm.NewOrm() // ORM数据库操作
	tableName, pk := conn.GetTableAndPk(model)
	sql := "select count(1) from " + tableName + where
	count := 0
	err := conn.Raw(sql).QueryRow(&count)
	if err != nil {
		logger.Error("查询数量发生错误：", err)
		return nil, &JsonMsg{false, "查询数量发生错误：", 1}
	}

	sql = "select * from " + tableName + where + " order by " + pk + " desc " + limit
	tableData, err := conn.Raw(sql).QueryMaps()
	if err != nil {
		logger.Error("查询数据发生错误：", err)
		return nil, &JsonMsg{false, "查询数据发生错误：", 1}
	}

	return &Page{true, "数据查询成功", 0, count, tableData}, nil
}

//判断用户请求是否正确
func JsonCheckRequest(_ http.ResponseWriter, r *http.Request) (map[string]interface{}, *JsonMsg) {
	inputJson, msg := TokenCheckRequest(r)
	if msg != nil {
		return nil, msg
	}

	currentPage := inputJson["currentPage"]
	pageSize := inputJson["pageSize"]

	pageNum := 1
	if currentPage != nil {
		pageNum = int(currentPage.(float64))
	}
	if pageNum < 1 {
		return nil, &JsonMsg{false, "页码必须从第1页开始", 1}
	}

	sizeNum := 10
	if pageSize != nil {
		sizeNum = int(pageSize.(float64))
	}
	if sizeNum < 1 {
		return nil, &JsonMsg{false, "每页记录条数必须大于0", 1}
	}

	searchs := inputJson["searchs"]
	if searchs != nil {
		searchArr, ok := searchs.([]interface{})
		if !ok {
			return nil, &JsonMsg{false, "searchs参数错误，应为数组类型", 1}
		}

		if len(searchArr) > 0 {
			for _, searchMap := range searchArr {
				_, ok := searchMap.(map[string]interface{})
				if !ok {
					return nil, &JsonMsg{false, "JSON", 1}
				}
			}
		}
	}

	return inputJson, nil
}

// 查询项转成sql查询条件
func SerachJsonToSql(inputJson map[string]interface{}) ([]string, string) {
	page := 1
	size := 20
	if inputJson["currentPage"] != nil {
		page = int(inputJson["currentPage"].(float64))
	}
	if inputJson["pageSize"] != nil {
		size = int(inputJson["pageSize"].(float64))
	}
	limit := (page - 1) * size
	limitStr := fmt.Sprintf(" limit %d,%d", limit, size)

	searchs := inputJson["searchs"]
	if searchs == nil {
		return nil, limitStr
	}

	wheres := make([]string, 0)

	for _, search := range searchs.([]interface{}) {
		searchMap, _ := search.(map[string]interface{})
		name := searchMap["name"].(string)
		searchType := searchMap["searchType"].(string)
		dataType := searchMap["dataType"].(string)
		value := searchMap["value"].(string)
		isDanger := common.CheckSQLInject(value, true)
		if isDanger {
			continue // 忽略此条查询项
		}

		if dataType != "NUM" && searchType != "LK" {
			value = "'" + value + "'"
		}

		switch searchType {
		case "EQ": //等于
			wheres = append(wheres, common.GoNameToDbName(name)+" = "+value)
		case "LK": //类似
			wheres = append(wheres, common.GoNameToDbName(name)+" like '%"+value+"%'")
		case "LT": // 小于或等于
			wheres = append(wheres, common.GoNameToDbName(name)+"<="+value)
		case "GT": // 大于或等于, 方便日期型(不带时间部分)字段查询
			wheres = append(wheres, common.GoNameToDbName(name)+">="+value)
		case "NULL": // 为空
			wheres = append(wheres, common.GoNameToDbName(name)+"=''")
		case "NOTNULL": // 非空
			wheres = append(wheres, common.GoNameToDbName(name)+"!=''")
		}
	}
	return wheres, limitStr
}

// 回显Model
func EchoModel(w http.ResponseWriter, r *http.Request, model interface{}) (string, map[string]interface{}, map[string]interface{}) {
	inputJson, msg := EchoCheckRequest(w, r, model)
	if msg != nil {
		return msg.Msg, nil, nil
	}

	retJson := map[string]interface{}{}
	retJson["success"] = true
	retJson["msg"] = "回显成功"
	retJson["status"] = "0"
	action := inputJson["action"].(string)
	if action == "edit" {
		conn := orm.NewOrm()
		table, pk := conn.GetTableAndPk(model)
		sql := "select * from " + table + " where " + pk + "=?"

		err := conn.Raw(sql, inputJson[pk]).QueryRow(model)
		if err != nil {
			logger.Error("编辑model发生错误", err)
			return "编辑model发生错误" + err.Error(), nil, nil
		}
		retJson["model"] = model
	} else {
		retJson["model"] = GetModelDefJson(model)
	}
	return "", inputJson, retJson
}
func EchoCallBak(w http.ResponseWriter, r *http.Request, model interface{}) {
	msg, _, echoModel := EchoModel(w, r, model)
	if msg != "" {
		ServeJSON(w, JsonMsg{false, msg, 1})
	} else {
		ServeJSON(w, echoModel)
	}
}

//判断用户回显请求是否正确
func EchoCheckRequest(_ http.ResponseWriter, r *http.Request, model interface{}) (map[string]interface{}, *JsonMsg) {
	inputJson, msg := TokenCheckRequest(r)
	if msg != nil {
		return nil, msg
	}

	action := inputJson["action"]
	if action == nil {
		return nil, &JsonMsg{false, "请求Action不能为空", 1}
	}

	if action == "edit" {
		// 编辑状态下 主键不能为空
		_, pk := orm.NewOrm().GetTableAndPk(model)
		pkValue := inputJson[pk]
		if pkValue == nil {
			return nil, &JsonMsg{false, "编辑状态下主键不能为空", 1}
		}
	}

	return inputJson, nil
}

//获取Ext界面需要的JSON字符串
func GetModelDefJson(mode interface{}) map[string]interface{} {
	v := reflect.ValueOf(mode).Elem()
	t := v.Type()
	data := map[string]interface{}{}
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		input := field.Tag.Get("input")
		if input != "no" { //用户输入字段
			value, _ := GetFieldDefByTag(field)
			data[common.StrFirstToLower(t.Field(i).Name)] = value
		}
	}
	return data
}

//从Tag读取默认值
func GetFieldDefByTag(f reflect.StructField) (string, error) {
	value := f.Tag.Get("orm")
	if value == "" {
		return "", nil
	} else {
		var def = ""
		temp := strings.Split(value, ";")
		for _, str := range temp {
			if strings.HasPrefix(str, "default(") {
				beginIndex := strings.Index(str, "default(")
				endIndex := strings.Index(str, ")")
				def = string([]byte(str)[beginIndex+8 : endIndex])
			}
		}
		return def, nil
	}
}

// 新增单条记录
func CreateRecord(w http.ResponseWriter, r *http.Request, model interface{}) {
	inputJson, msg := SaveCheckRequest(w, r)
	if msg != nil {
		ServeJSON(w, msg)
		return
	}

	modelMap := inputJson["model"].(map[string]interface{})
	JsonToStruct(modelMap, model)
	conn := orm.NewOrm()
	_, err := conn.Insert(model)
	if err != nil {
		logger.Error("新增记录发生错误", err)
		ServeJSON(w, JsonMsg{false, "新增记录发生错误" + err.Error(), 1})
		return
	}

	ServeJSON(w, JsonMsg{true, "新增成功", 0})
}

// 更新单条记录
func EditRecord(w http.ResponseWriter, r *http.Request, model interface{}) {
	inputJson, msg := SaveCheckRequest(w, r)
	if msg != nil {
		ServeJSON(w, msg)
		return
	}

	modelMap := inputJson["model"].(map[string]interface{})
	conn := orm.NewOrm()
	table, pk := conn.GetTableAndPk(model)
	sql := "select * from " + table + " where " + pk + " = ?"
	err := conn.Raw(sql, modelMap[pk]).QueryRow(model)
	if err != nil {
		logger.Error("更新失败，按主键查询发生错误", err)
		ServeJSON(w, JsonMsg{false, "更新失败，按主键查询发生错误" + err.Error(), 1})
		return
	}

	JsonToStruct(modelMap, model)
	_, err = conn.Update(model)
	if err != nil {
		logger.Error("编辑记录发生错误", err)
		ServeJSON(w, JsonMsg{false, "编辑记录发生错误" + err.Error(), 1})
		return
	}

	ServeJSON(w, JsonMsg{true, "编辑成功", 0})
}

//json数据赋值给结构体
func JsonToStruct(jsonMap map[string]interface{}, model interface{}) {
	val := reflect.ValueOf(model).Elem()
	for k, v := range jsonMap {
		field := val.FieldByName(common.StrFirstToUpper(k))
		if field.IsValid() {
			common.SetFieldValue(field, v)
		}
	}
}

// 检查保存参数是否正确
func SaveCheckRequest(_ http.ResponseWriter, r *http.Request) (map[string]interface{}, *JsonMsg) {
	inputJson, msg := TokenCheckRequest(r)
	if msg != nil {
		return nil, msg
	}

	model := inputJson["model"]

	if model == nil {
		return nil, &JsonMsg{false, "请求保存数据不能为空", 1}
	}

	return inputJson, nil
}

// 删除记录集
func DeleteModel(_ http.ResponseWriter, r *http.Request, model interface{}, conn orm.Ormer, extraField ...string) (string, map[string]interface{}) {
	inputJson, msg := DeleteCheckRequest(r)
	if msg != nil {
		return msg.Msg, nil
	}

	ids := inputJson["ids"].(string)
	tableName, pk := conn.GetTableAndPk(model)
	sql := "delete from " + tableName + " where " + pk + " in (" + ids + ")"
	if extraField != nil {
		sql += " or " + extraField[0] + " in ('" + ids + "')"
	}

	_, err := conn.Raw(sql).Exec()
	if err != nil {
		_ = conn.Rollback()
		logger.Error("删除失败", err)
		return "删除失败" + err.Error(), nil
	}

	return "", inputJson
}

// 删除记录集 (参数由外部提供)
func DeleteModelWithInputJson(inputJson map[string]interface{}, model interface{}, conn orm.Ormer, extraWhere string, extraField ...string) string {
	ids := inputJson["ids"].(string)
	tableName, pk := conn.GetTableAndPk(model)
	sql := "delete from " + tableName + " where (" + pk + " in (" + ids + ")"
	if extraField != nil {
		sql += " or " + extraField[0] + " in ('" + ids + "')"
	}
	sql += ")"
	if extraWhere != "" {
		sql += " and " + extraWhere
	}

	_, err := conn.Raw(sql).Exec()
	if err != nil {
		_ = conn.Rollback()
		logger.Error("删除失败", err)
		return "删除失败" + err.Error()
	}

	return ""
}
func DeleteCallBak(w http.ResponseWriter, r *http.Request, model interface{}) {
	conn := orm.NewOrm()
	msg, _ := DeleteModel(w, r, model, conn)
	if msg != "" {
		ServeJSON(w, JsonMsg{false, msg, 1})
	} else {
		ServeJSON(w, JsonMsg{true, "删除成功", 0})
	}
}

//判断用户删除请求是否正确
func DeleteCheckRequest(r *http.Request) (map[string]interface{}, *JsonMsg) {
	inputJson, msg := TokenCheckRequest(r)
	if msg != nil {
		return nil, msg
	}

	ids := inputJson["ids"]
	if ids == nil {
		return nil, &JsonMsg{false, "请求ids不能为空", 1}
	}

	return inputJson, nil
}
